package com.dly.blog.service.impl;

import com.dly.blog.domain.*;
import com.dly.blog.domain.ro.menu.RouterQuery;
import com.dly.blog.domain.ro.permission.PermissionAddRO;
import com.dly.blog.domain.vo.RouteVO;
import com.dly.blog.domain.vo.menu.MenuTreeVO;
import com.dly.blog.exception.CommonExceptionEnum;
import com.dly.blog.exception.GlobalException;
import com.dly.blog.mapper.*;
import com.dly.blog.service.MenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dly.blog.utile.CollectionUtils;
import com.dly.blog.utile.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import com.dly.blog.domain.vo.menu.MenuVO;
import com.dly.blog.domain.ro.menu.MenuPageRO;
import com.dly.blog.domain.ro.menu.MenuAddRO;
import com.dly.blog.domain.ro.menu.MenuEditRO;
import com.dly.blog.domain.vo.PageVO;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.transaction.annotation.Transactional;
import lombok.AllArgsConstructor;
import cn.hutool.core.collection.ListUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author DLY
 * @since 2024-11-04 17:08:58
 */
@Service
@AllArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    private final RoleMenuMapper roleMenuMapper;

    private final RoleMapper roleMapper;

    private final PermissionMapper permissionMapper;

    private final MenuPermissionMapper menuPermissionMapper;

    private final RolePermissionMapper rolePermissionMapper;

    @Override
    public PageVO<MenuVO> getMenuPage(MenuPageRO menuPageRO) {
        Page<Menu> page = baseMapper.selectPage(menuPageRO.buildIPage(), new LambdaQueryWrapper<Menu>().isNull(Menu::getParentId));
        List<Menu> menus = baseMapper.selectList(new LambdaQueryWrapper<>());
        return PageVO.buildMyBatis(page, menu -> {
            MenuVO menuVO = new MenuVO();
            BeanUtils.copyProperties(menu, menuVO);
            menuVO.setChildren(buildMenuTree(menus, menu.getId()));
            return menuVO;
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMenu(MenuAddRO menuAddRO) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuAddRO, menu);
        menu.setQuery(JsonUtils.writeToJson(menuAddRO.getQuery()));
        baseMapper.insert(menu);

        //插入页面相关的按钮权限
        menuAddRO.getButtons()
                .forEach(permissionAddRO -> {
                    Permission permission = new Permission();
                    BeanUtils.copyProperties(permissionAddRO, permission);
                    permissionMapper.insert(permission);

                    //插入关系
                    MenuPermission menuPermission = new MenuPermission();
                    menuPermission.setPermissionId(permission.getId());
                    menuPermission.setMenuId(menu.getId());
                    menuPermissionMapper.insert(menuPermission);
                });

        String admin = roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleCode, "admin")).getId();
        RoleMenu roleMenu = new RoleMenu();
        roleMenu.setRoleId(admin);
        roleMenu.setMenuId(menu.getId());
        roleMenuMapper.insert(roleMenu);
    }

    @Override
    public MenuVO getMenu(String id) {
        Menu menu = baseMapper.selectById(id);
        MenuVO menuVO = new MenuVO();
        BeanUtils.copyProperties(menu, menuVO);
        return menuVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeMenu(String[] ids) {
        baseMapper.deleteBatchIds(ListUtil.toList(ids));
        menuPermissionMapper.delete(new LambdaQueryWrapper<MenuPermission>().in(MenuPermission::getMenuId, ListUtil.toList(ids)));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editMenu(MenuEditRO menuEditRO) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuEditRO, menu);
        menu.setQuery(JsonUtils.writeToJson(menuEditRO.getQuery()));
        baseMapper.updateById(menu);

        //更新权限
        List<String> permissionCodes = menuEditRO.getButtons().stream().map(PermissionAddRO::getPermissionCode).toList();

        if(permissionCodes.isEmpty()){
            //清除原来的
            menuPermissionMapper.delete(new LambdaQueryWrapper<MenuPermission>().eq(MenuPermission::getMenuId, menu.getId()));
            return;
        }

        //查询以及添加了的permissionCode
        List<Permission> permissions = Optional.of(permissionMapper
                .selectList(new LambdaQueryWrapper<Permission>().in(Permission::getPermissionCode, permissionCodes))
                .stream()
                .toList()).orElse(new ArrayList<>());

        List<String> oldPermissionCode = permissions.stream().map(Permission::getPermissionCode).toList();
        List<String> newPermissionIds = permissions.stream().map(Permission::getId).collect(Collectors.toCollection(ArrayList::new));

        menuEditRO.getButtons().stream()
                .filter(button-> !oldPermissionCode.contains(button.getPermissionCode()))
                .forEach(button-> {
                    Permission permission = new Permission();
                    BeanUtils.copyProperties(button, permission);
                    permissionMapper.insert(permission);
                    newPermissionIds.add(permission.getId());
                });


        List<String> oldPermissionIds =
                Optional.of(menuPermissionMapper.selectList(new LambdaQueryWrapper<MenuPermission>().eq(MenuPermission::getMenuId, menu.getId())).stream().map(MenuPermission::getPermissionId).collect(Collectors.toCollection(ArrayList::new)))
                        .orElse(new ArrayList<>());

        CollectionUtils.getDifferenceResult(oldPermissionIds, newPermissionIds);
        //删除老的
        oldPermissionIds.forEach(old-> {
            menuPermissionMapper
                    .delete(new LambdaQueryWrapper<MenuPermission>()
                            .eq(MenuPermission::getMenuId, menu.getId())
                            .eq(MenuPermission::getPermissionId, old)
                    );
            //清除
            permissionMapper.deleteById(old);
            //清除角色权限关系
            rolePermissionMapper.delete(new LambdaQueryWrapper<RolePermission>().eq(RolePermission::getPermissionId, old));
        });
        //插入新的
        newPermissionIds.forEach(now->{
            MenuPermission menuPermission = new MenuPermission();
            menuPermission.setMenuId(menu.getId());
            menuPermission.setPermissionId(now);
            menuPermissionMapper.insert(menuPermission);
        });
    }

    @Override
    public List<MenuTreeVO> getAllMenu() {
        List<Menu> menus = baseMapper.selectList(
                new LambdaQueryWrapper<Menu>()
                        .eq(Menu::getConstant, 0)
                        .eq(Menu::getStatus, '1')
        );
        return buildMenuTreeVO(menus, null);
    }

    private List<MenuTreeVO> buildMenuTreeVO(List<Menu> menus, String pId) {
        return menus.stream()
                .filter(menu -> StringUtils.equals(menu.getParentId(),pId))
                .map(menu -> {
                    List<MenuTreeVO> children = buildMenuTreeVO(menus, menu.getId());
                    MenuTreeVO menuTreeVO = new MenuTreeVO();
                    menuTreeVO.setId(menu.getId());
                    menuTreeVO.setLabel(menu.getMenuName());
                    menuTreeVO.setPId(pId);
                    menuTreeVO.setChildren(children);
                    return menuTreeVO;
                })// 按 order 排序
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getAllPages() {
        return baseMapper.selectList(new LambdaQueryWrapper<Menu>().eq(Menu::getMenuType, '2'))
                .stream()
                .map(Menu::getRouteName).toList();
    }

    private List<MenuVO> buildMenuTree(List<Menu> menus, String parentId){
        return menus.stream()
                .filter(menu -> StringUtils.equals(menu.getParentId(),parentId))
                .map(menu -> {
                    List<MenuVO> children = buildMenuTree(menus, menu.getId());
                    MenuVO menuVO = new MenuVO();
                    BeanUtils.copyProperties(menu, menuVO);
                    Optional.ofNullable(menu.getQuery()).ifPresent(query-> menuVO.setQuery(JsonUtils.readFromJsonString(query, new TypeReference<>() {})));
                    menuVO.setButtons(buildButton(menu.getId()));
                    menuVO.setChildren(children);
                    return menuVO;
                })// 按 order 排序
                .collect(Collectors.toList());
    }

    private List<PermissionAddRO> buildButton(String menuId){
        List<String> permissionIds = Optional.of(menuPermissionMapper.selectList(new LambdaQueryWrapper<MenuPermission>().eq(MenuPermission::getMenuId, menuId)).stream().map(MenuPermission::getPermissionId).toList()).orElse(new ArrayList<>());
        if(permissionIds.isEmpty()){
            return new ArrayList<>();
        }
        return permissionMapper.selectBatchIds(permissionIds).stream().map(permission -> {
            PermissionAddRO permissionAddRO = new PermissionAddRO();
            BeanUtils.copyProperties(permission, permissionAddRO);
            return permissionAddRO;
        }).toList();
    }
}
